// META: title=test WebNN API transpose operation
// META: global=window,dedicatedworker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
// META: script=../resources/utils.js
// META: timeout=long

'use strict';

// https://www.w3.org/TR/webnn/#api-mlgraphbuilder-transpose
// Permute the dimensions of the input tensor according to the permutation
// argument.
//
// dictionary MLTransposeOptions {
//   sequence<[EnforceRange] unsigned long> permutation;
// };
//
// MLOperand transpose(
//     MLOperand input, optional MLTransposeOptions options = {});


const getTransposePrecisionTolerance = (graphResources) => {
  const toleranceValueDict = {float32: 0, float16: 0};
  const expectedDataType =
      getExpectedDataTypeOfSingleOutput(graphResources.expectedOutputs);
  return {metricType: 'ULP', value: toleranceValueDict[expectedDataType]};
};

const transposeTests = [
  {
    'name': 'transpose float32 1D constant tensor default options',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'},
          'constant': true
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments': [{'input': 'transposeInput'}],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 1D tensor default options',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments': [{'input': 'transposeInput'}],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 2D tensor default options',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [4, 6], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments': [{'input': 'transposeInput'}],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797, 1.8434585332870483, 46.38539123535156,
            99.46284484863281,  53.45924758911133,  92.8102798461914,
            -84.89764404296875, -87.58920288085938, -60.118492126464844,
            56.100074768066406, 56.70438766479492,  -65.3779067993164,
            38.081748962402344, 77.05838012695312,  -25.695144653320312,
            -66.00990295410156, 78.64247131347656,  57.46807861328125,
            5.62217378616333,   38.466827392578125, -69.25324249267578,
            -84.74308776855469, -25.66281509399414, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [6, 4], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 3D tensor default options',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [2, 3, 4], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments': [{'input': 'transposeInput'}],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797,  46.38539123535156,   78.64247131347656,
            5.62217378616333,    56.100074768066406,  -65.3779067993164,
            53.45924758911133,   -84.89764404296875,  -69.25324249267578,
            -25.66281509399414,  77.05838012695312,   -66.00990295410156,
            -60.118492126464844, 56.70438766479492,   1.8434585332870483,
            99.46284484863281,   57.46807861328125,   38.466827392578125,
            38.081748962402344,  -25.695144653320312, 92.8102798461914,
            -87.58920288085938,  -84.74308776855469,  2.1999382972717285
          ],
          'descriptor': {'dimensions': [4, 3, 2], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 4D tensor default options',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [1, 2, 3, 4], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments': [{'input': 'transposeInput'}],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797,  46.38539123535156,   78.64247131347656,
            5.62217378616333,    56.100074768066406,  -65.3779067993164,
            53.45924758911133,   -84.89764404296875,  -69.25324249267578,
            -25.66281509399414,  77.05838012695312,   -66.00990295410156,
            -60.118492126464844, 56.70438766479492,   1.8434585332870483,
            99.46284484863281,   57.46807861328125,   38.466827392578125,
            38.081748962402344,  -25.695144653320312, 92.8102798461914,
            -87.58920288085938,  -84.74308776855469,  2.1999382972717285
          ],
          'descriptor': {'dimensions': [4, 3, 2, 1], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 5D tensor default options',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [1, 2, 1, 3, 4], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments': [{'input': 'transposeInput'}],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797,  46.38539123535156,   78.64247131347656,
            5.62217378616333,    56.100074768066406,  -65.3779067993164,
            53.45924758911133,   -84.89764404296875,  -69.25324249267578,
            -25.66281509399414,  77.05838012695312,   -66.00990295410156,
            -60.118492126464844, 56.70438766479492,   1.8434585332870483,
            99.46284484863281,   57.46807861328125,   38.466827392578125,
            38.081748962402344,  -25.695144653320312, 92.8102798461914,
            -87.58920288085938,  -84.74308776855469,  2.1999382972717285
          ],
          'descriptor': {'dimensions': [4, 3, 1, 2, 1], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 1D tensor options.permutation',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments':
            [{'input': 'transposeInput'}, {'options': {'permutation': [0]}}],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [24], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 2D tensor options.permutation',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [4, 6], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments':
            [{'input': 'transposeInput'}, {'options': {'permutation': [1, 0]}}],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797, 1.8434585332870483, 46.38539123535156,
            99.46284484863281,  53.45924758911133,  92.8102798461914,
            -84.89764404296875, -87.58920288085938, -60.118492126464844,
            56.100074768066406, 56.70438766479492,  -65.3779067993164,
            38.081748962402344, 77.05838012695312,  -25.695144653320312,
            -66.00990295410156, 78.64247131347656,  57.46807861328125,
            5.62217378616333,   38.466827392578125, -69.25324249267578,
            -84.74308776855469, -25.66281509399414, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [6, 4], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 3D tensor options.permutation',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [2, 3, 4], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments': [
          {'input': 'transposeInput'}, {'options': {'permutation': [2, 0, 1]}}
        ],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797,  78.64247131347656,  56.100074768066406,
            46.38539123535156,   5.62217378616333,   -65.3779067993164,
            53.45924758911133,   -69.25324249267578, 77.05838012695312,
            -84.89764404296875,  -25.66281509399414, -66.00990295410156,
            -60.118492126464844, 1.8434585332870483, 57.46807861328125,
            56.70438766479492,   99.46284484863281,  38.466827392578125,
            38.081748962402344,  92.8102798461914,   -84.74308776855469,
            -25.695144653320312, -87.58920288085938, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [4, 2, 3], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 4D tensor options.permutation',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [1, 2, 3, 4], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments': [
          {'input': 'transposeInput'},
          {'options': {'permutation': [2, 3, 0, 1]}}
        ],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797, 46.38539123535156,   53.45924758911133,
            -84.89764404296875, -60.118492126464844, 56.70438766479492,
            38.081748962402344, -25.695144653320312, 78.64247131347656,
            5.62217378616333,   -69.25324249267578,  -25.66281509399414,
            1.8434585332870483, 99.46284484863281,   92.8102798461914,
            -87.58920288085938, 56.100074768066406,  -65.3779067993164,
            77.05838012695312,  -66.00990295410156,  57.46807861328125,
            38.466827392578125, -84.74308776855469,  2.1999382972717285
          ],
          'descriptor': {'dimensions': [3, 4, 1, 2], 'dataType': 'float32'}
        }
      }
    }
  },
  {
    'name': 'transpose float32 5D tensor options.permutation',
    'graph': {
      'inputs': {
        'transposeInput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [1, 2, 1, 3, 4], 'dataType': 'float32'}
        }
      },
      'operators': [{
        'name': 'transpose',
        'arguments': [
          {'input': 'transposeInput'},
          {'options': {'permutation': [1, 3, 0, 4, 2]}}
        ],
        'outputs': 'transposeOutput'
      }],
      'expectedOutputs': {
        'transposeOutput': {
          'data': [
            -45.67443084716797,  53.45924758911133,  -60.118492126464844,
            38.081748962402344,  78.64247131347656,  -69.25324249267578,
            1.8434585332870483,  92.8102798461914,   56.100074768066406,
            77.05838012695312,   57.46807861328125,  -84.74308776855469,
            46.38539123535156,   -84.89764404296875, 56.70438766479492,
            -25.695144653320312, 5.62217378616333,   -25.66281509399414,
            99.46284484863281,   -87.58920288085938, -65.3779067993164,
            -66.00990295410156,  38.466827392578125, 2.1999382972717285
          ],
          'descriptor': {'dimensions': [2, 3, 1, 4, 1], 'dataType': 'float32'}
        }
      }
    }
  }
];

if (navigator.ml) {
  transposeTests.forEach((test) => {
    webnn_conformance_test(
        buildGraphAndCompute, getTransposePrecisionTolerance, test);
  });
} else {
  test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
}
